<html lang="en"> <head> <script src="https://d3js.org/d3.v3.js"></script> </head> <body>
    <script type="text/javascript" charset="utf-8">
        var nodes = [{name: "桂林"}, {name: "广州"}, {name: "厦门"}, {name: "杭州"}, {name: "上海"}, {name: "青岛"}, {name: "天津"}];
        var edges = [{source: 0, target: 1}, {source: 0, target: 2}, {source: 0, target: 3}, {source: 1, target: 4}, {source: 1, target: 5}, {source: 1, target: 6}];
        // 节点是一些城市名, 连线的两端是节点的序号（序号从 0 开始）
        var width = 400, height = 400;
        var svg = d3.select("body").append("svg").attr("width", width).attr("height", height);
        var force = d3.layout.force()
            .nodes(nodes) // 指定节点数组
            .links(edges) // 指定连线数组
            .size([width, height]) // 指定范围
            .linkDistance(150) // 指定连线长度
            .charge(-400); // 相互之间的作用力
        force.start(); // 开始作用
        console.log(nodes, edges);
        // index: 节点的索引号, px, py: 节点上一个时刻的坐标, x, y: 节点的当前坐标, weight: 节点的权重
        // 接下来是添加 连线, 节点, 文字
        // 添加连线
        var svg_edges = svg.selectAll("line").data(edges).enter().append("line")
            .style("stroke", "#ccc")
            .style("stroke-width", 1);
        var color = d3.scale.category20();
        // 添加节点
        var svg_nodes = svg.selectAll("circle").data(nodes).enter().append("circle")
            .attr("r", 20)
            .style("fill", function(d, i) {
                return color(i);
            })
            .call(force.drag); // 使得节点能够拖动
        // 调用 call( force.drag ) 后节点可被拖动。force.drag() 是一个函数, 将其作为 call() 的参数, 相当于将当前选择的元素传到 force.drag() 函数中。
        // 添加描述节点的文字
        var svg_texts = svg.selectAll("text").data(nodes).enter().append("text")
            .style("fill", "black")
            .attr("dx", 20)
            .attr("dy", 8)
            .text(function(d) {return d.name;});
        // 力导向图布局 force 有一个事件 tick, 每进行到一个时刻, 都要调用它, 更新的内容就写在它的监听器里就好
        // tick 的英文意思是钟表发出的嘀嗒嘀嗒声, 想到这个大家应该很清楚了吧。每次触发时, 都会调用后面的无名函数
        force.on("tick", function() { // 对于每一个时间间隔
            // 更新连线坐标
            svg_edges.attr("x1", function(d) { return d.source.x; })
                .attr("y1", function(d) { return d.source.y; })
                .attr("x2", function(d) { return d.target.x; })
                .attr("y2", function(d) { return d.target.y; });
            // 更新节点坐标
            svg_nodes.attr("cx", function(d) { return d.x; })
                .attr("cy", function(d) { return d.y; });
            // 更新文字坐标
            svg_texts.attr("x", function(d) { return d.x; })
                .attr("y", function(d) { return d.y; });
        });
    </script> </body> </html>
